home *** CD-ROM | disk | FTP | other *** search
- /*******************************************\
- * file: ReportUtils.c *
- * version: 1.0ß *
- * *
- * Common routines for printing reports *
- * *
- * ----------------------------------------- *
- * By: Donald Koscheka *
- * Date: 30-OCT-89 *
- * © Copyright 1989, Donald Koscheka *
- * All Rights Reserved *
- * *
- * ----------------------------------------- *
- \*******************************************/
-
- #include <MacTypes.h>
- #include <MemoryMgr.h>
- #include <ResourceMgr.h>
- #include <OSUtil.h>
- #include <HyperXCmd.h>
- #include <HyperUtils.h>
- #include <PrintMgr.h>
- #include <ReportUtils.h>
-
- /****************************************************/
- /* --- MISCELLANEOUS UTILITIES --- */
- /* */
- /****************************************************/
-
- short getStringHandleSize( h )
- Handle h;
- /******************************
- * In hypercard, strings are padded
- * out to even boundaries so that the
- * handle size may be longer than
- * you'd like.
- *
- * This routine returns the length
- * of the string up to but not
- * including the NULL
- *
- * This routine is to be used for
- * NULL terminated strings only!
- *
- *******************************/
- {
- short i = 0;
- char *endPoint;
-
- if( validHandle( h ) ){
- i = (short)GetHandleSize( h );
-
- endPoint = *h + i - 1;
- while( *endPoint ){
- --i;
- --endPoint;
- }
- }
- return( i );
- }
-
-
-
- short strNComp( s1, s2, len )
- char *s1;
- char *s2;
- long len;
- /******************************
- *
- ******************************/
- {
- short indx;
- short match = 1;
-
- for( indx = 1; indx <= len; indx++ )
- if( *s1++ != *s2++ ){
- match = 0;
- break;
- }
- return( match );
- }
-
- /****************************************************/
- /* --- PARSING ROUTINES --- */
- /* */
- /****************************************************/
-
-
- long matchToken( buf, tabl )
- Handle buf;
- short tabl;
- /******************************
- * given an input buffer and the resource
- * id of the parse table, return
- * the token that represents the input
- * string.
- *
- * A token of 0 is returned if no
- * match is found. This way, you
- * can use the first item in the list
- * as the default item!
- *
- * The symbol table should have the
- * format:
- *
- * <string>, <token>
- *
- * where string mathces to the input
- * string and token is that value for
- * a given match.
- ******************************/
- {
- char *bp; /*** pointer to input strings ***/
- char *tp;
- Handle strH; /*** handle to parse strings resource ***/
- long token = 0; /*** return the default if no match ***/
- short indx = 0;
- short theID;
- ResType theType;
- short done = 0;
- long len;
- char theNum[31];
- char *np;
- char theName[256];
- char theString[256];
-
- bp = *buf;
-
- tp = bp;
- while( *tp ){
- toupper( *tp );
- tp++;
- }
-
- strH = GetResource( STRING_TYPE, tabl );
-
- if( strH ){
-
- GetResInfo( strH, &theID, &theType, &theName );
-
- /*** compare the string to the allowable tokens ***/
- indx = 1 ;
-
- while( !done ){
- theString[0] = '\0';
- GetIndString( &theString, tabl, indx );
-
- if( theString[0] == '\0' ) /* no strings matched the input */
- done = 1;
- else{ /* attempt to match to current str */
-
- PtoCstr( (char *)&theString );
-
- len = 0;
-
- bp = theString;
- while ( *bp != ',' ){
- bp++;
- len++;
- }
-
- if( strncmp( *buf, (char *)theString, len ) == 0){
- /* have a match so extract the token */
-
- /*** move past any garbage in the string ***/
- while( (*bp < '0' || *bp > '9') && *bp != '-')
- bp++;
-
- /*** now copy what bp points to into a ***/
- /*** a pascal style string ***/
-
- theNum[0] = '\0';
- np = &theNum[1];
-
- while( *bp >= '0' && *bp <= '9' ){
- theNum[0]++;
- *np++ = *bp++;
- }
-
- /*** np is a valid p-string ***/
- StringToNum( theNum, &token );
- done = 1;
- }
- else
- indx++;
- }
- }
- }
-
- return( token );
- }
-
-
- long parseNum( bp )
- char *bp;
- /******************************
- * parse the data stream
- * and return a numeric
- * value. The stream is null
- * terminated.
- *
- ******************************/
- {
- long num = 0;
-
- char theString[256];
- short done = 0;
- char *ps;
-
- /*** move the input pointer until we're looking at a number ***/
- while( *bp && ( *bp < '0' || *bp > '9' ) && *bp != '-' )
- bp++;
-
- /*** copy the data into a pascal string ***/
- ps = theString;
- ps++;
-
- while( *bp >= '0' && *bp <= '9' )
- *ps++ = *bp++;
-
- /*** moved one past the output so try this ***/
- theString[0] = (char)( ps - theString -1 );
- StringToNum( theString, &num );
-
- return( num );
- }
-
-
-
- char *nextToken( bp )
- char *bp;
- /******************************
- * given a pointer to an
- * input stream, move to the
- * next token in the stream.
- *
- * Token's are delineated by
- * ',' or whitespace
- *
- * Assumes we are pointing to the current token
- * Move past the current token and the white
- * space that follows it.
- ******************************/
- {
- /*** move past the current token ***/
- while( *bp &&(*bp != ',' && *bp != SPACE && *bp != CR && *bp != LF && *bp != TAB) )
- bp++;
-
- /*** move past the white space to the next token ***/
- while( *bp == ',' || *bp == SPACE || *bp == CR || *bp == LF || *bp == TAB )
- bp++;
-
- return( bp );
- }
-
-
-
- void parseRect( buf, theRect )
- Handle buf;
- Rect *theRect;
- /******************************
- * parse the data stream
- * into a rectangle
- ******************************/
- {
- char *bp;
-
- HLock( buf );
-
- bp = *buf;
- theRect->top = parseNum( bp );
- bp = nextToken( bp );
-
- theRect->left = parseNum( bp );
- bp = nextToken( bp );
-
- theRect->bottom = parseNum( bp );
- bp = nextToken( bp );
-
- theRect->right = parseNum( bp );
- bp = nextToken( bp );
-
- HUnlock( buf );
- }
-
-
-
- void CopyRect( r1, r2 )
- Rect *r1;
- Rect *r2;
- /****************************
- * copy rectangle r1 to r2
- *
- ****************************/
- {
- r2->top = r1->top;
- r2->left = r1->left;
- r2->bottom = r1->bottom;
- r2->right = r1->right;
- }
-
-
-
- /****************************************************/
- /* --- PRINTING UTILITIES --- */
- /* */
- /****************************************************/
-
-
-
-
-
-
-
- void FootNotePage( pp )
- pInfoPtr pp;
- /******************************
- * draw the footnote for this page
- ******************************/
- {
- Handle theText;
- footPtr myFoot;
- short siz;
- FontInfo fInfo;
- short hite;
- GrafPtr oldPort;
- styleSet footStyle;
- char thePage[32];
- char theNum[32];
- Rect temp;
-
- if( pp->footNote.hite ){
- CopyRect( &(pp->margin), &temp );
-
- SetMargin( pp, 0, 0, 0 ,0 );
-
- GetPort( &oldPort );
- SetPort( (GrafPtr)(pp->prPort) );
-
- PenNormal();
-
- footStyle.Font = TIMES;
- footStyle.Size = 12;
- footStyle.Style= PLAIN_TEXT;
- footStyle.Just = teJustLeft;
-
- SetFontStyles( pp, (stylePtr)&footStyle );
-
- GetFontInfo( &fInfo );
- hite = fInfo.ascent + fInfo.descent + fInfo.leading;
-
- /*** draw the company name and the version number ***/
- if( theText = pp->footNote.key1 ){
- MoveTo( pp->margin.left, pp->margin.bottom+(2*hite)-4 );
- siz = getStringHandleSize( theText );
-
- HLock( theText );
- DrawTextRun( pp, *theText, siz, teJustLeft );
- HUnlock( theText );
- }
-
- if( theText = pp->footNote.key2 ){
- MoveTo( pp->margin.left, pp->margin.bottom+(2*hite)-4);
- siz = getStringHandleSize( theText );
-
- HLock( theText );
- DrawTextRun( pp, *theText, siz, teJustRight );
- HUnlock( theText );
- }
-
- /*** draw the date and the page number ***/
- if( theText = pp->footNote.key3 ){
- MoveTo( pp->margin.left, pp->margin.bottom+(3*hite)-4);
- siz = getStringHandleSize( theText );
-
- HLock( theText );
- DrawTextRun( pp, *theText, siz, teJustLeft );
- HUnlock( theText );
- }
-
- if( pp->pagecount ){
- thePage[0] = '\0';
- MoveTo( pp->margin.left, pp->margin.bottom+(3*hite)-4);
- strcat( thePage, "Page #");
- NumToString( (long)pp->pagecount, theNum );
-
- PtoCstr( (char *)&theNum );
- strcat( thePage, theNum );
- DrawTextRun( pp, thePage, strlen( thePage ), teJustRight );
- }
-
- CopyRect( &temp, &(pp->margin) );
- SetFontStyles( pp, (stylePtr)&(pp->defaultStyle) );
- SetPort( oldPort );
- }
- }
-
-
-
- void EjectPage( pp )
- pInfoPtr pp;
- /******************************
- * Eject the current page and
- * adjust the rectangle
- * accordingly
- *
- ******************************/
- {
-
- FootNotePage( pp );
-
- PrClosePage( pp->prPort );
-
- pp->pagecount++;
- pp->totalpages++;
-
- if( pp->totalpages == 128 ){
- TPPrPort tp;
- PrCloseDoc( pp->prPort );
-
- tp = PrOpenDoc( pp->prRecHandle, NIL, NIL );
- pp->prPort = (GrafPtr)tp;
- pp->totalpages = 0;
- SetPort( (GrafPtr)tp );
- }
-
- PrOpenPage( pp->prPort, NIL );
-
- pp->curntPen.h = pp->margin.left;
- pp->curntPen.v = pp->margin.top;
- }
-
-
- void NewLine( pp, y )
- pInfoPtr pp;
- short y;
- /******************************
- * Move to a new position on the
- * page checking for page break.
- ******************************/
- {
- CheckPageBreak( pp, y );
- pp->curntPen.h = pp->margin.left;
- pp->curntPen.v += y;
- MoveTo( pp->curntPen.h, pp->curntPen.v );
- }
-
-
- void CheckPageBreak( pp, y )
- pInfoPtr pp;
- short y;
- /******************************
- * Check to see if the current line
- * will fit on the page, break the
- * page if not.
- *
- * This routine manages the pen
- * updating.
- *
- * √ 10.31.89
- ******************************/
- {
- if( (pp->curntPen.v + y) >= pp->margin.bottom ){
- EjectPage( pp );
- NewLine( pp, y );
- }
-
- /* pp->curntPen.v += y; */
- }
-
-
-
-
-
-
- /****************************************************/
- /* --- PORT UTILITIES --- */
- /* */
- /****************************************************/
-
-
-
- void SetMargin( pp, t, l, b, r )
- pInfoPtr pp;
- short t;
- short l;
- short b;
- short r;
- /******************************
- * Reset the margin rectangle in
- * the printing rect.
- *
- * We add to top left and subtract
- * from bottom right.
- *
- * if no parameters specified, then
- * set the margin to the page margin.
- *
- * 11.7.89 adjust bottom margin for
- * footer hite
- ******************************/
- {
- register TPPrint tp = *(pp->prRecHandle);
-
- pp->margin.top = tp->prInfo.rPage.top + t;
- pp->margin.left = tp->prInfo.rPage.left + l;
- pp->margin.bottom = tp->prInfo.rPage.bottom - b - pp->footNote.hite;
- pp->margin.right = tp->prInfo.rPage.right - r;
- }
-
-
-
- void SetFont( sp, theFont )
- stylePtr sp;
- short theFont;
- /*******************************
- * Reset the font for this document
- *******************************/
- {
- if( theFont )
- sp->Font = theFont;
- else
- sp->Font = DEFAULT_FONT;
- }
-
-
-
- void SetFontSize( sp, theSize )
- stylePtr sp;
- short theSize;
- /*******************************
- * Set the font size for this document
- *******************************/
- {
- if( theSize )
- sp->Size = theSize;
- else
- sp->Font = DEFAULT_SIZE;
- }
-
-
-
- void SetFontStyle( sp, theStyle )
- stylePtr sp;
- short theStyle;
- /*******************************
- * Style is cumulative. To reset it
- * you must set it to plain text.
- *******************************/
- {
- if( theStyle )
- sp->Style &= theStyle;
- else
- sp->Style = PLAIN_TEXT;
- }
-
-
-
- void SetFontJust( sp, theJust )
- stylePtr sp;
- short theJust;
- /*******************************
- *
- *******************************/
- {
-
- if( theJust )
- sp->Just = theJust;
- else
- sp->Just = teJustLeft;
- }
-
-
-
- void SetFontStyles( pp, sp )
- pInfoPtr pp;
- stylePtr sp;
- /*******************************
- * facilitation piece. requires some
- * thinking yet (not fully happy with
- * the data abstractions I've developed
- * to this point-- 11.1.89)
- *******************************/
- {
- GrafPtr oldPort;
-
- GetPort( &oldPort );
- SetPort( (GrafPtr)(pp->prPort) );
-
- TextFont( sp->Font );
- TextSize( sp->Size );
- TextFace( sp->Style );
-
- SetPort( oldPort );
- }
-
-
-
- void DrawTextRun( pp, tx, len, just )
- pInfoPtr pp;
- char *tx;
- short len;
- short just;
- /**********************************
- * Draw the given run of text taking
- * without breaking the page.
- **********************************/
- {
- short pagewidth = pp->margin.right - pp->margin.left;
- short twidth;
-
- /*** need to know the pixel width of the line ***/
- twidth = TextWidth( tx, 0, len );
-
- switch( just ){
- case teJustLeft:
- break;
-
- case teJustRight:
- Move( (pagewidth - twidth), 0 );
- break;
-
- case teJustCenter:
- Move( (pagewidth - twidth)/2, 0 );
- break;
-
- case teJustFill:
- /*** doesn't do anything yet ***/
- break;
- }/* switch */
-
- DrawText( tx, 0, len );
- }
-
-
-
- void PrintString( pp, theText, hite )
- pInfoPtr pp;
- Handle theText;
- short hite;
- /*******************************
- * draw the text object passed in
- * as a parameter.
- *
- * titles are always followed by
- * blank lines so double the hite
- *******************************/
- {
- short siz;
- FontInfo fInfo;
-
- NewLine( pp, hite );
- siz = getStringHandleSize( theText );
- DrawTextRun( pp, *theText, siz, teJustLeft );
- NewLine( pp, hite );
- SetFontStyles( pp, (stylePtr)&(pp->defaultStyle) );
- }
-
-
-
-
- void DrawTextLine( pp, tx, len, hite, just )
- pInfoPtr pp;
- char *tx;
- short len;
- short hite;
- short just;
- /**********************************
- * Draw the given run of text taking
- * into account page breaks if necessary.
- *
- * handles justification for the line.
- *
- * A line is defined as having constant
- * vertical position so we only have to move
- * the pen horizontally on a line to fit
- * it into the correct format.
- **********************************/
- {
- NewLine( pp, hite );
- DrawTextRun( pp, tx, len, just );
- }
-
-
-
- void DrawLeftMargin( pp, theLeft, hite )
- pInfoPtr pp;
- Handle theLeft;
- short hite;
- /*******************************
- * Margins and style are set before
- * calling this routine.
- *
- * EXPERIMENTAL ROUTINE.
- *******************************/
- {
- Rect temp;
-
- /*** Draw the labels and answer portions ***/
- if( theLeft && (GetHandleSize( theLeft )) ){
- CopyRect( &(pp->margin), &temp );
-
- pp->margin.right = temp.left - 12;
- MoveTo( pp->margin.left, pp->curntPen.v );
-
- HLock( theLeft );
- DrawTextRun( pp, *theLeft, getStringHandleSize(theLeft ), teJustRight );
- HUnlock( theLeft );
-
- CopyRect( &temp, &(pp->margin) );
-
- SetHandleSize( theLeft, 0L );
- }
- }
-
-
-
- void DrawRightMargin( pp, theRight, hite )
- pInfoPtr pp;
- Handle theRight;
- short hite;
- /*******************************
- * the answer gets printed "in the
- * margin"
- *
- * EXPERIMENTAL ROUTINE.
- *******************************/
- {
- Rect temp;
- register TPPrint tp = *(pp->prRecHandle);
-
- /*** Draw the labels and answer portions ***/
- if( theRight && (GetHandleSize( theRight )) ){
- CopyRect( &(pp->margin), &temp );
-
- pp->margin.left = pp->margin.right + 30;
- pp->margin.right= tp->prInfo.rPage.right;
- MoveTo( pp->margin.left, pp->curntPen.v );
-
- HLock( theRight);
- DrawTextRun( pp, *theRight, getStringHandleSize(theRight), teJustLeft );
- HUnlock( theRight);
- MoveTo( pp->curntPen.h, pp->curntPen.v );
-
- CopyRect( &temp, &(pp->margin) );
-
- SetHandleSize( theRight, 0L );
- }
- }
-
-
-
- char *EndOfWord( wPtr, hardline )
- char *wPtr;
- short *hardline;
- /******************************
- * Given a pointer to a word, calculate the
- * length of the next word in the run. The length
- * is determined by adding the width of each
- * character together until a word break.
- *
- * The difference between tpos and wpos is always
- * one word (including the sticky characters)
- *
- * IN: Pointer to text
- * wPtr == pointer to NEXT word in
- * run (or NIL if No next word)
- *
- * adjusts the output ptr which will
- * be pointing to the word break character.
- *
- * first occurrance of space is considered
- * part of the word.
- ******************************/
- {
- *hardline = 0;
-
- while( 1 ){
- switch( (short)*wPtr ){
- case NULL:
- return( wPtr );
- break;
-
- case QUOTE:
- case COMMA:
- case PERIOD:
- case TAB:
- case SPACE:
- case ';':
- case '!':
- case '?':
- ++wPtr;
- return( wPtr );
- break;
-
- case CR:
- case FF:
- ++wPtr;
- *hardline = 1;
- return( wPtr );
- break;
-
- default:
- ++wPtr;
- break;
- }/*** switch( *wPtr ) ****/
- }/*** while(1) ****/
- }
-
-
-
- void FlushLine( pp, lineStart, len, just, theLeft, theRight, hite )
- pInfoPtr pp;
- char *lineStart;
- short len;
- short just;
- Handle theLeft;
- Handle theRight;
- short hite;
- /*******************************
- * Flush the current line out to
- * the printer.
- *
- *******************************/
- {
- if( len ){
- CheckPageBreak( pp, hite );
- NewLine( pp, hite );
- DrawLeftMargin( pp, theLeft, hite );
- DrawRightMargin( pp, theRight, hite );
- DrawTextRun( pp, lineStart, len, just );
- }
- }
-
-
-
-
- void DrawParagraph( pp, theText, theLeft, theRight )
- pInfoPtr pp;
- Handle theText;
- Handle theLeft;
- Handle theRight;
- /*******************************
- * Draw the text. In effect, theLeft
- * is the text to the left of the
- * paragraph and theRight is text
- * to the right of the paragraph.
- *
- * Margins and style are set before
- * calling this routine.
- *
- * EXPERIMENTAL ROUTINE.
- *******************************/
- {
- short siz;
- FontInfo fInfo;
- short hite;
- GrafPtr oldPort;
- char *lineStart;
- char *lineEnd;
- char *nextWord;
- short lineWidth = 0;
- short wordWidth = 0;
- short theMargin;
- short just;
- short hardline;
- short wid;
-
- GetPort( &oldPort );
- SetPort( (GrafPtr)(pp->prPort) );
-
- GetFontInfo( &fInfo );
- hite = fInfo.ascent + fInfo.descent + fInfo.leading;
-
- NewLine( pp, hite );
- siz = getStringHandleSize( theText );
-
- just = pp->curntStyle.Just;
- theMargin = pp->margin.right - pp->margin.left;
-
- HLock( theText );
-
- nextWord = lineStart = lineEnd = *theText;
-
- while( *nextWord ){
-
- /*** loop invariant: lineEnd >= lineStart */
- nextWord = EndOfWord( lineEnd, &hardline );
- wordWidth = TextWidth( lineEnd, 0, (short)((long)nextWord-(long)lineEnd) );
-
- if( wordWidth + lineWidth <= theMargin )
- lineWidth += wordWidth;
- else{
- wid = (short)((long)lineEnd - (long)lineStart);
- FlushLine(pp, lineStart,wid,just,theLeft,theRight,hite);
- lineWidth = wordWidth;
- lineStart = lineEnd;
- }
-
- if( hardline ){
- lineEnd = nextWord;
- wid = (short)((long)lineEnd - (long)lineStart);
- FlushLine( pp, lineStart, wid, just, theLeft, theRight, hite);
- lineWidth = 0;
- lineStart = lineEnd;
- /*CheckPageBreak( pp, hite );
- NewLine( pp, hite );
- */
- }
-
- lineEnd = nextWord;
-
- }/* while( *nextword ) */
-
- /*** whatever is left in the buffer will fit on one line ***/
- FlushLine( pp,lineStart,(short)(lineEnd-lineStart),just,theLeft,theRight,hite);
-
- HUnlock( theText );
- SetPort( oldPort );
- }
-
-
-
-
-
-
-
-